package sparrow.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import java.io.IOException;
import java.io.StringReader;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML.Attribute;

import sparrow.common.Topic;
import sparrow.common.TopicHistory;


public class ChatHistoryPane extends JPanel {
	private JScrollPane sp;
	private ChatHistoryTextPane tp;
	private ColorChooser cc;
	TopicHistory th;
	
	public ChatHistoryPane(TopicHistory th) {
		super(new BorderLayout());
		this.th = th;
		
		tp = new ChatHistoryTextPane(this);
		sp = new JScrollPane(tp);
		sp.setAutoscrolls(true);
		cc = new ColorChooser(tp, th);
		add(sp, BorderLayout.CENTER);
		add(cc, BorderLayout.SOUTH);
		
		setVisible(true);
	}
	
	void reportClick(int id, int rgb, Element elm) {
		// TODO communicate with backend
		Topic topic = th.findTopic(rgb);
		if (topic != null)
			cc.label.setText(topic.label());
		else
			rgb = th.getLastColor();
		cc.setColor(new Color(rgb));
		
		if (!cc.isVisible()) { 
			cc.setBlock(id, elm);
			cc.setVisible(true);
		} else {
			cc.actionPerformed(null);
			tp.setBlockColor(id, rgb, elm);
		}
	}
	
	void reportMouseExit() {
//		cc.setVisible(false);
	}
	
	public void appendMessage(String sender, String time, String msg, ImageIcon icon) {
		tp.appendMessage(sender, time, msg, icon);
	}
}

class ColorChooser extends JPanel implements ActionListener {
	
	private ChatHistoryTextPane tp;
	private Color color;
	private JLabel colorPatch;
	JTextField label;
	private JButton apply;
	private int id;
	private Element elm;
	private TopicHistory th;
	
	public ColorChooser(ChatHistoryTextPane tp, TopicHistory th) {
		this.tp = tp;
		this.th = th;
		
		label = new JTextField(12);
		add(label);
		colorPatch = new JLabel("     ");
		colorPatch.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
		colorPatch.setOpaque(true);
		colorPatch.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				color = new Color(ColorChooser.this.th.getLastColor());
			    Color newColor = JColorChooser.showDialog(
                        ColorChooser.this,
                        "Choose Background Color",
                        color);
			    if (!newColor.equals(color))
			    	label.setText(null);
			    setColor(newColor);
			}
		});
		add(colorPatch);
		
		apply = new JButton("Apply!");
		apply.addActionListener(this);
		add(apply);
		
		setColor(Color.lightGray);
		
		setVisible(false);
	}
	
	public void setBlock(int id, Element elm) {
		this.id = id;
		this.elm = elm;
	}
	
	public void setColor(Color c) {
		color = c;
		colorPatch.setBackground(c);
	}
	
	public void actionPerformed(ActionEvent e) {
		int colorRGB = getRGB();
		Topic topic = th.findTopic(colorRGB);
		if (topic == null)
			th.addTopic(label.getText(), colorRGB, id);
		else {
			topic.setLabel(label.getText());
			colorRGB = topic.color();
		}
		if (elm != null)
			tp.setBlockColor(id, colorRGB, elm);
		setVisible(false);
	}
	
	int getRGB() {
		return color.getRGB() & ((1 << 24) - 1);
	}
}

class ChatHistoryTextPane extends JTextPane {

	private Style labelStyle, msgStyle;
//	private StyledDocument doc;
	private HTMLDocument doc;
	private HTMLEditorKit editor;
	private int msgCount = 0;
	private ChatHistoryPane parent;
	
	public ChatHistoryTextPane(ChatHistoryPane p) {
		parent = p;
		
		setContentType("text/html");
		doc = (HTMLDocument)getStyledDocument();
		editor = (HTMLEditorKit)getEditorKit();
		
		msgStyle = doc.addStyle("msgStyle", null);
		StyleConstants.setFontFamily(msgStyle, "SansSerif");
		StyleConstants.setFontSize(msgStyle, 10);
		
		labelStyle = doc.addStyle("labelStyle", msgStyle);
		StyleConstants.setBold(labelStyle, true);
		
		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				int pos = getCaretPosition();
				Element elm = doc.getParagraphElement(pos);
				int id = Integer.parseInt((String)elm.getAttributes().getAttribute(Attribute.ID)),
					rgb = Integer.parseInt((String)elm.getAttributes().getAttribute(Attribute.BGCOLOR), 16);
//				System.out.println("caret = " + pos);
//				System.out.println(elm);
//				System.out.println(id);
				highlightBlock(id, elm);
				parent.reportClick(id, rgb, doc.getElement(Integer.toString(id)));
			}
			
			public void mouseExited(MouseEvent e) {
				parent.reportMouseExit();
			}
		});

		setEditable(false);
	}
	
	void setBlockColor(int id, int color, Element elm) {
		String msg = getMessage(id),
		label = getLabel(id);
		String msgTxt = formatMessage(label, msg, color, id);
//		System.out.println(color);
//		System.out.println(msg);
//		System.out.println(label);
//		System.out.println(msgTxt);
		try {
			doc.setOuterHTML(elm, msgTxt);
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (BadLocationException ex) {
			ex.printStackTrace();
		}
	}
	
	void highlightBlock(int id, Element elm) {
		String msg = getMessage(id),
			label = getLabel(id);
		String msgTxt = formatMessage(label, msg, 0xFFFF00, id);
		try {
			doc.setOuterHTML(elm, msgTxt);
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (BadLocationException ex) {
			ex.printStackTrace();
		}
	}
	
	private String getLabel(int id) {
		HTMLDocument.RunElement elm = (HTMLDocument.RunElement)doc.getElement("lbl"+id);
		int start = elm.getStartOffset(),
			end = elm.getEndOffset();
		try {
			return doc.getText(start, end-start);
		} catch (BadLocationException e) {
			return null;
		}
	}
	
	private String getMessage(int id) {
		HTMLDocument.RunElement elm = (HTMLDocument.RunElement)doc.getElement("msg"+id);
		int start = elm.getStartOffset(),
			end = elm.getEndOffset();
		try {
			return doc.getText(start, end-start);
		} catch (BadLocationException e) {
			return null;
		}
	}
	
	private String formatMessage(String label, String msg, int color, int id) {
		return String.format("<div id=\"%d\" bgcolor=\"%s\"><b>" +
				"<span id=\"lbl%d\">%s</span>:</b> <span id=\"msg%d\">%s</span></div>",
				id, Integer.toString(color, 16), id, label, id, msg);
	}
	
	public void appendMessage(String sender, String time, String msg, ImageIcon icon) {
		// TODO sanitize msg for html tags
		String str = formatMessage(sender, msg, parent.th.getLastColor(), msgCount);
		
		try {
			editor.read(new StringReader(str), doc, doc.getLength());
		} catch (IOException e) {
			System.err.println("Error parsing html string");
		} catch (BadLocationException e) {
			System.err.println("Error writing to chat history");
		}
		
		setCaretPosition(doc.getLength());	// cause parent to auto scroll
		
		// add to topic history
		parent.th.addMessage(msg, time, msgCount);
		if (parent.th.findTopic(parent.th.getLastColor()) == null)
			parent.th.addTopic(parent.th.getLastColor(), msgCount);
		msgCount += 1;
	}
}

